from application.decorators import login_required, admin_required
from google.appengine.api import taskqueue
from google.appengine.ext import db
from application.models import *
from application import reader
from application import settings
from datetime import datetime, timedelta
from flask import request, redirect, url_for
import logging

'''
using @admin_required here will cause problem in GAE production env
'''
def q_mark_as_read():
    user_key_str = request.form['user_key']
    item_key_str = request.form['item_key']

    if user_key_str and item_key_str:
        user_key = None
        user = None
        item_key = None
        item = None

        try:
            user_key = db.Key(encoded=user_key_str)
            user = User.get(user_key)
            item_key = db.Key(encoded=item_key_str)
            item = Item.get(item_key)
        except:
            logging.error("Can't get user/item, userkey=%s, itemkey=%s", user_key_str, item_key_str)
            return 'Error'

        reader.mark_item_readed(user_key, item_key)
        return 'Ok'
    else:
        logging.error('user_key_str or item_key_str is missing')
        return 'Error'

def q_fetch_channel():
    ''' Fetch channel in queue '''
    channel_key_str = request.form['channel_key']

    if channel_key_str:
        # convert to db.Key and get channel
        channel_key = None
        channel = None
        try:
            channel_key = db.Key(encoded=channel_key_str)
            channel = db.get(channel_key)
        except:
            pass
        # verify the channel
        if channel == None or channel.kind() != 'Channel':
            logging.error("channel is None or channel.kind() is not 'Channel', key_str=%s", channel_key_str)
            return 'Error'
        else:
            # verify subscriber users
            user_q = channel.subscribe_set
            if user_q.count() < 1:
                logging.info('channel subscribers < 1, channel_key=%s', channel_key_str)
                return 'No subscriber, skip fetching'
            else:
                # do the fetch
                logging.info('fetching channel_key=%s', channel_key_str)
                reader.fetch_channel(channel_key)
                return 'Ok'
    else:
        logging.error('channel_key_str is missing!')
        return 'Error'

def cron_fetch_all():
    channel_q = Channel.all(keys_only=True)
    for channel_key in channel_q:
        logging.info('fetch_channel_key=%s', str(channel_key))
        taskqueue.add(url='/q_fetch_channel', params={'channel_key': str(channel_key)})
    return 'Ok'

def cron_clean_old():
    channel_q = Channel.all(keys_only=True)
    for channel_key in channel_q:
        # loop channel
        # TBD: add sorting by fetch_time here and process until out-of-condition
        item_q = Item.all()
        item_q.ancestor(channel_key)
        if item_q.count(limit=settings.KEEP_LEAST_ITEMS+1) < settings.KEEP_LEAST_ITEMS:
            # DO NOT clean any channel that items less than settings.KEEP_LEAST_ITEMS items
            logging.info('bypass this channel, items too few')
            pass
        else:
            item_q.filter('fetch_time <', datetime.now() - timedelta(days=settings.ITEM_CLEAN_DAYS))
            for item in item_q:
                # Bypass any item have star on it
                star_item_q = item.star_item_set
                if star_item_q.count(limit=1) > 0:
                    continue
                # Bypass any item have unread on it
                unread_item_q = item.unread_item_set
                if unread_item_q.count(limit=1) > 0:
                    continue

                logging.info('Deleteing item, key=%s', str(item.key()))
                # clean associated star mark
                for star_item in star_item_q:
                    star_item.delete()
                # clean associated unread mark
                for unread_item in unread_item_q:
                    unread_item.delete()
                # clean associated readed mark
                readed_item_q = item.readed_item_set
                for readed_item in readed_item_q:
                    readed_item.delete()
                # delete item
                item.delete()
    return "Ok"

def cron_invalid_maggic():
    maggic_q = Maggic.all()
    maggic_q.filter('invalid =', False)
    current_time = datetime.now()
    for maggic in maggic_q:
        gen_timedelta = current_time - maggic.generate_time
        if gen_timedelta > timedelta(minutes=60):
            logging.info('make magic invalid maggic=%s', str(maggic.maggic_id))
            maggic.invalid = True
            maggic.put()

    return 'Ok'